// cf-542f
// 题意：给定n(<=1000)个任务，每个任务有个需要时间ti(<=T<=100)和价值qi。
//       现在有若干人要来做这个任务，做之前每个人都要从某个问题开始回答
//       'yes'或'no'，任意种回答都会可能转移到下一个问题或者任务上，回答
//       一个问题需要一分钟。这些人很忙，所以回答问题的时间加上做任务的
//       时间不可以超过T。初始也可以没有问题直接就是任务。（相当于要
//       构造一棵二叉树，中间节点是问题，任务放在叶子节点上）。
//
// 题解：一个不错的问题。可以用dp或者贪心做。
//       如果用贪心做，其实很像哈夫曼树的构造过程。我们从时间最小的任务且
//       价值最大的任务开始，如果有和它时间想等且价值次大的任务，假设两个
//       任务为(t, v1), (t, v2)，那么我们可以把它们合并成(t+1, v1+v2)，
//       根据贪心肯定是最好的。否则就把(t, v1)变成(t+1, v1)。
//       不断这样反复到合并为一个任务为止。中间如果t<=T那么更新答案。
//       复杂度应该是O(n*log(n))。
//
//       如果用动态规划做就是假设dp[i][v]表示第i有v个节点的最大价值。
//       转移就是在第i层选k个最大节点，那么我们dp[i][v]去更新
//       dp[i-1][(v+k)/2]。最后答案是dp[0][1]。
//       复杂度是O(n^2*T)。
//       
// run: $exec < input
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <queue>

using pair_type = std::pair<int, int>;
int n, t;

void print(std::vector<pair_type> const & v)
{
	for (auto i : v) std::cerr << "{" << i.first << ", " << i.second << "}  ";
	std::cerr << '\n';
}

int main()
{
	std::cin >> n >> t;
	auto cmp = [](pair_type const & a, pair_type const & b) {
		return a.first > b.first || (a.first == b.first && a.second < b.second);
	};
	std::priority_queue<pair_type, std::vector<pair_type>, decltype(cmp)> pq(cmp);

	int ans = 0;
	for (int i = 0, cost, value; i < n; i++) {
		std::cin >> cost >> value;
		pq.push({cost, value});
		if (cost <= t) ans = std::max(ans, value);
	}

	while (pq.size() > 1) {
		auto t1 = pq.top(); pq.pop();
		auto t2 = pq.top();
		if (t1.first == t2.first) {
			pq.pop();
			auto tmp = std::make_pair(++t1.first, t1.second + t2.second);
			pq.push(tmp);
			if (tmp.first <= t) ans = std::max(ans, tmp.second);
		} else
			pq.push({++t1.first, t1.second});
	}
	std::cout << ans << '\n';
}

